package com.lesofn.runner;

import com.google.common.hash.Hashing;
import com.google.common.io.Files;
import com.lesofn.constant.DSLConstant;
import com.lesofn.entity.InvokeEntity;
import com.lesofn.util.PathUtils;
import com.lesofn.util.excel.ExcelImportUtil;
import dsl.groovy.DslDelegate;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import groovy.util.logging.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.runtime.InvokerHelper;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author lesofn
 * @version 1.0 2021-03-02 11:59
 */
@Slf4j
@SuppressWarnings("UnstableApiUsage")
public class GroovyScriptRunner {
    private static final Map<Long, Script> SCRIPT_MAP = new ConcurrentHashMap<>();
    public static final ThreadLocal<Binding> bindingThreadLocal = new ThreadLocal<>();

    public static List<Script> getScript(String module, String api, Map<String, Object> params) {
        return getScript(module, api, "dsl", params);
    }

    public static List<Script> getScript(String module, String api, String rootDir, Map<String, Object> params) {
        //简单的通过api是否包含"."来判断其是否是全文件名
        String apiFullName = api.split("\\.").length > 1 ? api : api + ".groovy";

        String path = rootDir + "/" + module + "/" + apiFullName;
        List<Script> base = getScriptByPath(path);
        List<Script> resultScripts = Lists.newArrayList();
        for (Script script : base) {
            Binding binding = new Binding();
            binding.setProperty(DSLConstant.MODULE, module);
            binding.setProperty(DSLConstant.API, api);
            params.forEach(binding::setVariable);
            bindingThreadLocal.set(binding);
            resultScripts.add(InvokerHelper.createScript(script.getClass(), binding));
        }
        return resultScripts;
    }

    private static List<Script> getScriptByPath(String path) {
        CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
        compilerConfiguration.setScriptBaseClass(DslDelegate.class.getName());
        GroovyShell shell = new GroovyShell(GroovyScriptRunner.class.getClassLoader());
        try {
            URL classpathUrl = GroovyScriptRunner.class.getClassLoader().getResource(path);
//            String filePath = PathUtils.parseFilePath(classpathUrl);
//            new File(classpathUrl.toURI());
            File file = new File(classpathUrl.toURI());
            Charset charset = Charset.forName(compilerConfiguration.getSourceEncoding());
            List<String> lines = Files.readLines(file, charset);
            String templateContent = String.join("\n", lines);

            // content是模板，读取excel列表，将参数替换掉，再解析为多个script
            String dataFilePath = "C:\\Users\\Administrator\\Desktop\\1\\1.xlsx";
            FileInputStream fis = new FileInputStream(dataFilePath);
            List<InvokeEntity> invokeEntities = new ExcelImportUtil<InvokeEntity>(InvokeEntity.class).readExcel(fis, 1, 0);
            List<Script> scripts = Lists.newArrayList();
            for (InvokeEntity entity : invokeEntities) {
                String url = entity.getUrl();
                String appName = entity.getAppName();
                String times = entity.getTimes();
                String newContent = templateContent.replace("__url", "https://scmp.csair.com" + url)
//                String newContent = templateContent.replace("__url", "https://10.79.13.99" + url)
                        .replace("__appName", appName)
                        .replace("__times", times);

                final long hashing = Hashing.goodFastHash(128).hashBytes(newContent.getBytes()).asLong();
                if (SCRIPT_MAP.containsKey(hashing)) {
                    scripts.add(SCRIPT_MAP.get(hashing));
                    continue;
                }
                Script script = shell.parse(newContent);
                SCRIPT_MAP.put(hashing, script);
                scripts.add(script);
            }
            return scripts;
        } catch (IOException | URISyntaxException e) {
            throw new RuntimeException("getScript error,path: " + path, e);
        }
    }
}